#ifndef RAFT_CORE_RAFT_H
#define RAFT_CORE_RAFT_H

#include <boost/serialization/string.hpp>
#include <boost/serialization/vector.hpp>
#include "boost/serialization/serialization.hpp"
#include "boost/any.hpp"
#include <chrono>
#include <cmath>
#include <iostream>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
#include "applyMsg.h"       // 与上层状态机的通信消息（日志应用通知）
#include "persister.h"      // 状态持久化抽象（落盘到磁盘/内存）
#include "config.h"         // 项目配置（如超时时间、集群参数等）
#include "raftRpcUtil.h"    // 一对一 RPC 连接工具（每个节点独立通道）
#include "util.h"           // 工具函数（如日志索引转换、时间工具等）
#include "monsoon.h"

namespace raftCore 
{
/*
 * @brief 网络状态表示（仅用于调试，生产环境可移除）
 * Disconnected: 网络分区或节点不可达（用于标记异常节点，防止 matchIndex 异常回退）
 * AppNormal: 网络正常（默认状态，确保日志复制进度正常更新）
 * 注：实际 Raft 协议不依赖此状态，仅用于辅助调试网络抖动问题
 */
constexpr int Disconnected = 0;  
constexpr int AppNormal = 1;

/*
 * @brief 投票请求处理状态（Candidate 跟踪每个 Follower 的响应）
 * Killed: 竞选者被终止（如收到更高任期的 RPC，当前 Candidate 失效）
 * Voted: Follower 已为本轮任期投票（避免重复投票）
 * Expire: 投票请求过期（任期号 < 当前任期，忽略）
 * Normal: 正常未处理状态（等待 Follower 响应）
 * 注：用于优化选举的并发控制，减少无效 RPC
 */
constexpr int Killed = 0;
constexpr int Voted  = 1;   //本轮已经投过票了
constexpr int Expire = 2;   //投票（消息、竞选者）过期
constexpr int Normal = 3;

class Raft : public raftRpcProctoc::raftRpc {
private:
    /*
     * @brief 本地处理 AppendEntries RPC 请求（由 Leader 发送，用于日志复制和心跳）
     * @param args 请求参数（包含 Leader 任期、日志条目等信息）
     * @param reply 响应结果（包含处理状态、任期等信息）
     */
    void AppendEntries1(const raftRpcProctoc::AppendEntriesArgs *args, 
                        raftRpcProctoc::AppendEntriesReply *reply);    
    /*
     * @brief 日志应用定时器（定期将已提交日志应用到状态机）
     * 独立线程运行，周期性检查 commitIndex 并推送日志到 applyChan
     */
    void applierTicker();
    
    /*
     * @brief 发起选举（候选者状态下触发，向所有节点发送投票请求）
     */
    void doElection();

    /*
     * @brief 发起心跳（领导者状态下触发，定期向所有节点发送心跳包）
     * 用于维持 Leadership，避免其他节点触发新选举
     */
    void doHeartBeat();

    /*
     * @brief 选举超时定时器（跟随者/候选者状态下运行）
     * 若超时未收到 Leader 心跳，则转为候选者并发起选举
     */
    void electionTimeOutTicker();
    
    /*
     * @brief 获取待应用的日志条目（从 lastApplied 到 commitIndex）
     * @return 待应用的日志条目列表
     */
    std::vector<ApplyMsg> getApplyLogs();   // 状态机拉取待应用日志

    /*
     * @brief 获取新命令的日志索引（用于客户端提交命令时预分配索引）
     * @return 新日志的索引值
     */
    int getNewCommandIndex();

    /*
     * @brief 获取指定节点的前序日志信息（用于构建 AppendEntries 请求）
     * @param server 目标节点 ID
     * @param preIndex 输出参数，前序日志索引
     * @param preTerm 输出参数，前序日志任期
     */
    void getPrevLogInfo(int server, int *preIndex, int *preTerm);

    /*
     * @brief 领导者心跳定时器（定期触发心跳发送）
     * 确保在 HeartBeatTimeout 间隔内发送心跳，维持 Leadership
     */
    void leaderHearBeatTicker();
    
    /*
     * @brief 领导者向指定节点发送快照（当日志差距过大时使用）
     * @param server 目标节点 ID
     */
    void leaderSendSnapShot(int server);
    
    /*
     * @brief 领导者更新提交索引（根据多数节点已复制的日志索引）
     * 遵循 Raft 协议，仅提交本任期内的日志
     */
    void leaderUpdateCommitIndex();

    /*
     * @brief 检查日志是否匹配（用于验证日志一致性）
     * @param logIndex 日志索引
     * @param logTerm 日志对应的任期
     * @return 匹配返回 true，否则返回 false
     */
    bool matchLog(int logIndex, int logTerm);

    /*
     * @brief 持久化当前节点状态（任期、投票、日志等）
     * 调用 Persister 保存关键状态，防止节点重启后丢失
     */
    void persist();

    /*
     * @brief 检查日志是否更新（用于投票时判断候选者日志是否更完整）
     * @param index 待比较的日志索引
     * @param term 待比较的日志任期
     * @return 更完整返回 true，否则返回 false
     */
    bool UpToDate(int index, int term);

    /*
     * @brief 获取最后一条日志的索引
     * @return 最后一条日志的索引值
     */
    int getLastLogIndex();

    /*
     * @brief 获取最后一条日志的任期
     * @return 最后一条日志的任期号
     */
    int getLastLogTerm();

    /*
     * @brief 同时获取最后一条日志的索引和任期
     * @param lastLogIndex 输出参数，最后日志索引
     * @param lastLogTerm 输出参数，最后日志任期
     */
    void getLastLogIndexAndTerm(int *lastLogIndex, int *lastLogTerm);
    
    /*
     * @brief 根据日志索引获取对应的任期
     * @param logIndex 日志索引
     * @return 对应日志的任期号（无效索引返回 -1）
     */
    int getLogTermFromLogIndex(int logIndex);

    /*
     * @brief 将日志索引转换为本地日志数组的下标（考虑快照偏移）
     * @param logIndex 日志索引
     * @return 本地数组的下标值
     */
    int getSlicesIndexFromLogIndex(int logIndex);

    /*
     * @brief 发送请求投票 RPC 到指定节点
     * @param server 目标节点 ID
     * @param args 投票请求参数
     * @param reply 投票响应结果
     * @param votedNum 已获得的票数计数器（原子更新）
     * @return RPC 发送成功返回 true，否则返回 false
     */
    bool sendRequestVote(int server, std::shared_ptr<raftRpcProctoc::RequestVoteArgs> args,
                        std::shared_ptr<raftRpcProctoc::RequestVoteReply> reply, 
                        std::shared_ptr<int> votedNum);  

    /*
     * @brief 发送 AppendEntries RPC 到指定节点
     * @param server 目标节点 ID
     * @param args 日志复制请求参数
     * @param reply 响应结果
     * @param appendNums 已成功复制的节点计数器（原子更新）
     * @return RPC 发送成功返回 true，否则返回 false
     */
    bool sendAppendEntries(int server, std::shared_ptr<raftRpcProctoc::AppendEntriesArgs> args,
                        std::shared_ptr<raftRpcProctoc::AppendEntriesReply> reply, std::shared_ptr<int> appendNums);

    /*
     * @brief 将日志应用消息推送到 KV 服务器（上层应用）
     * @param msg 待推送的应用消息
     */
    void pushMsgToKvServer(ApplyMsg msg);

    /*
     * @brief 从持久化数据中恢复状态
     * @param data 持久化的二进制数据
     */
    void readPersist(std::string data);

    /*
     * @brief 获取当前需要持久化的数据（序列化后）
     * @return 序列化后的持久化数据
     */
    std::string persistData();
    
public:
    /*
     * @brief 获取当前节点的任期和角色状态
     * @param term 输出参数，当前任期号
     * @param isLeader 输出参数，是否为领导者
     */
    void GetState(int *term, bool *isLeader);

    /*
     * @brief 获取 Raft 状态的持久化数据大小
     * @return 数据大小（字节数）
     */   
    int GetRaftStateSize();

    /*
     * @brief 条件性安装快照（用于接收 Leader 发送的快照）
     * @param lastIncludedTerm 快照包含的最后日志任期
     * @param lastIncludedIndex 快照包含的最后日志索引
     * @param snapshot 快照数据
     * @return 安装成功返回 true，否则返回 false
     */
    bool CondInstallSnapshot(int lastIncludedTerm, int lastIncludedIndex, std::string snapshot);

    /*
     * @brief 处理 InstallSnapshot RPC 请求（由 Leader 发送，用于同步快照）
     * @param args 请求参数（包含快照数据、索引等信息）
     * @param reply 响应结果
     */
    void InstallSnapshot(const raftRpcProctoc::InstallSnapshotRequest *args,
                        raftRpcProctoc::InstallSnapshotResponse *reply);

    /*
     * @brief 处理 RequestVote RPC 请求（候选者发送，用于竞选领导者）
     * @param args 请求参数（包含候选者任期、日志信息等）
     * @param reply 响应结果（是否同意投票）
     */
    void RequestVote(const raftRpcProctoc::RequestVoteArgs *args, raftRpcProctoc::RequestVoteReply *reply);

    /*
     * @brief 启动新命令的日志复制流程（客户端接口）
     * @param command 待执行的命令
     * @param newLogIndex 输出参数，新日志的索引
     * @param newLogTerm 输出参数，新日志的任期
     * @param isLeader 输出参数，当前节点是否为领导者
     */
    void Start(common::Op command, int *newLogIndex, int *newLogTerm, bool *isLeader);

    /*
     * @brief 处理上层服务的快照请求（主动截断日志）
     * @param index 快照包含的最后日志索引
     * @param snapshot 快照数据（上层服务提供）
     * 功能：删除 index 之前的日志，保存快照，更新快照相关状态
     */
    void Snapshot(int index, std::string snapshot);

    /*
     * @brief 初始化 Raft 节点
     * @param peers 与其他节点通信的 RPC 工具列表
     * @param me 当前节点 ID
     * @param persister 持久化工具
     * @param applyCh 与上层服务通信的日志应用队列
     */
    void init(std::vector<std::shared_ptr<RaftRpcUtil>> peers, int me, 
            std::shared_ptr<Persister> persister,
            std::shared_ptr<common::LockQueue<ApplyMsg>> applyCh);

public:
    // 重写基类 RPC 方法（由 MPRPC 框架自动调用，反序列化后调用本地逻辑）
    void AppendEntries(google::protobuf::RpcController *controller, const ::raftRpcProctoc::AppendEntriesArgs *request,
                        ::raftRpcProctoc::AppendEntriesReply *response, ::google::protobuf::Closure *done) override;

    void InstallSnapshot(google::protobuf::RpcController *controller,
                        const ::raftRpcProctoc::InstallSnapshotRequest *request,
                        ::raftRpcProctoc::InstallSnapshotResponse *response, ::google::protobuf::Closure *done) override;

    void RequestVote(google::protobuf::RpcController *controller, const ::raftRpcProctoc::RequestVoteArgs *request,
                    ::raftRpcProctoc::RequestVoteReply *response, ::google::protobuf::Closure *done) override;

private:
    // 用于 Boost 序列化的持久化辅助类
    class BoostPersistRaftNode {
    public:
        friend class boost::serialization::access;
     
        /*
         * @brief Boost 序列化方法（保存/恢复 Raft 核心状态）
         * @param ar 序列化/反序列化器
         * @param version 序列化版本（兼容用）
         */
        template <class Archive>
        void serialize(Archive &ar, const unsigned int version) {
            ar &m_currentTerm;
            ar &m_votedFor;
            ar &m_lastSnapshotIncludeIndex;
            ar &m_lastSnapshotIncludeTerm;
            ar &m_logs;
        }
     
        int m_currentTerm;                        // 持久化的当前任期
        int m_votedFor;                           // 持久化的投票对象
        int m_lastSnapshotIncludeIndex;           // 持久化的快照最后索引
        int m_lastSnapshotIncludeTerm;            // 持久化的快照最后任期
        std::vector<std::string> m_logs;          // 持久化的日志条目
        std::unordered_map<std::string, int> umap; // 预留字段（未使用）
    };

private:
    std::mutex m_mtx;            // 线程互斥锁，保护所有共享状态
    std::vector<std::shared_ptr<RaftRpcUtil>> m_peers;    // 集群节点 RPC 连接池（下标 = 节点ID，0-based）
    std::shared_ptr<Persister> m_persister;     // 状态持久化工具（负责日志/任期/投票的落盘）
    int m_me;       // 当前节点 ID（集群唯一标识，0-based，如 0 表示自身）

    // -------------------- 所有角色具备的持久化状态 --------------------
    int m_currentTerm;      // 当前任期号（核心状态，所有节点维护，初始 0，每次选举+1）
    int m_votedFor;         // 本任期投票的候选者 ID（-1 表示未投票，用于防止重复投票）
    std::vector<raftRpcProctoc::LogEntry> m_logs;  // 日志条目数组（索引从 1 开始，0 保留给快照）
    int m_commitIndex;      // 已提交的最大日志索引（所有节点需同步）
    int m_lastApplied;      // 已应用到状态机的最大日志索引（与上层交互，避免重复应用）

    // -------------------- Leader 专有易失状态（无需持久化，重启后重建）--------------------
    std::vector<int> m_nextIndex;   // 下一个要发送给每个 Follower 的日志索引（下标=节点ID）
    std::vector<int> m_matchIndex;  // Follower 已复制的最大日志索引（下标=节点ID，用于计算 commitIndex）
    enum Status { Follower, Candidate, Leader };    // 三态状态机
    Status m_status;    // 当前角色（决定行为：Follower 等待 RPC，Candidate 拉票，Leader 发心跳）

    std::shared_ptr<common::LockQueue<ApplyMsg>> applyChan;  // 与上层服务通信的日志应用队列无锁队列（Raft→状态机的单向通道）

    // 快照相关状态（2D 特性）
    std::chrono::system_clock::time_point m_lastResetElectionTime;  // 选举超时基准时间（Follower/Candidate 维护）
    std::chrono::system_clock::time_point m_lastResetHearBeatTime;  // 心跳超时基准时间（Leader 维护）

    int m_lastSnapshotIncludeIndex;  // 快照包含的最后一条日志索引（快照后日志从 index+1 开始）
    int m_lastSnapshotIncludeTerm;   // 快照包含的最后一条日志任期（用于日志匹配）

    std::unique_ptr<fiber::IOManager> m_ioManager = nullptr;  // 协程管理器（用于异步 RPC 发送，提升吞吐量）
};

}   // namespace raftCore

#endif  // RAFT_CORE_RAFT_H